/*
 * Copyright 2016-2019 yoara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package yhao.infra.common;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * common层的配置类
 *
 * <ul>
 *     <li>redis配置定义</li>
 * </ul>
 * @author yoara
 */
public class ConfigFactory {
    private static Logger logger = LoggerFactory.getLogger(ConfigFactory.class);

    public static RedisSerializer keySerializer = new StringRedisSerializer();
    public static RedisSerializer hashKeySerializer = new StringRedisSerializer();

    public static void setCustomKeySerializer(RedisSerializer keySerializer) {
        ConfigFactory.keySerializer = keySerializer;
    }

    public static void setCustomHashKeySerializer(RedisSerializer hashKeySerializer) {
        ConfigFactory.hashKeySerializer = hashKeySerializer;
    }

    public static RedisTemplate makeRedisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setHashKeySerializer(hashKeySerializer);
        return redisTemplate;
    }

    private static JedisPoolConfig makeJedisPoolConfig(YhaoInfraCommonProperties.Redis redis) {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(redis.getPoolMaxTotal());
        config.setMaxIdle(redis.getPoolMaxIdle());
        config.setMaxWaitMillis(redis.getPoolMaxWaitMillis());
        return config;
    }

    /**
     * Redis可自定义集群加载模式
     */
    public static JedisConnectionFactory makeJedisConnectionFactory(
            YhaoInfraCommonProperties.Redis redis){
        JedisConnectionFactory factory;
        JedisPoolConfig poolConfig = makeJedisPoolConfig(redis);
        if (redis.isClusterEnable()) {
            RedisClusterConfiguration clusterConfig = getClusterConfig(redis.getUrl());
            clusterConfig.setPassword(redis.getPassword());
            factory = new JedisConnectionFactory(clusterConfig,poolConfig);
        } else {
            RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
            configuration.setHostName(redis.getUrl());
            configuration.setPort(redis.getPort());
            factory = new JedisConnectionFactory(configuration);
            factory.setPoolConfig(poolConfig);
        }
        if(StringUtils.isNotEmpty(redis.getPassword())){
            factory.setPassword(redis.getPassword());
        }
        factory.setDatabase(redis.getDbIndex());
        if(redis.getTimeout()>0){
            factory.setTimeout(redis.getTimeout());
        }
        loggerRedisInfo(redis);
        return factory;
    }

    /**
     * Lettuce自定义集群加载模式
     * @return
     */
    public static LettuceConnectionFactory makeLettuceConnectionFactory(YhaoInfraCommonProperties.Redis redis){
        LettuceConnectionFactory factory;
        if (redis.isClusterEnable()) {
            RedisClusterConfiguration clusterConfig = getClusterConfig(redis.getUrl());
            factory = new LettuceConnectionFactory(clusterConfig);
        } else {
            RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
            configuration.setHostName(redis.getUrl());
            configuration.setPort(redis.getPort());
            factory = new LettuceConnectionFactory();
        }
        if(StringUtils.isNotEmpty(redis.getPassword())){
            factory.setPassword(redis.getPassword());
        }
        factory.setDatabase(redis.getDbIndex());
        if(redis.getTimeout()>0){
            factory.setTimeout(redis.getTimeout());
        }
        loggerRedisInfo(redis);
        return factory;
    }

    private static RedisClusterConfiguration getClusterConfig(String envUrl) {
        RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration();
        String[] ips = envUrl.split(",");
        List<RedisNode> list = new ArrayList<>(ips.length * 2);
        for (String s : ips) {
            String[] nodes = s.trim().split(":");
            RedisNode node = new RedisNode(nodes[0].trim(), Integer.parseInt(nodes[1].trim()));
            list.add(node);
        }
        clusterConfig.setClusterNodes(list);
        clusterConfig.setMaxRedirects(ips.length);
        return clusterConfig;
    }

    private static void loggerRedisInfo(YhaoInfraCommonProperties.Redis redis){
        logger.info("===init "+redis.toString());
    }
}
